/*
 * @Author: 0x9DEFA478
 * @Date: 2022-01-22 23:04:45
 * @LastEditTime: 2022-04-15 14:22:14
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "./H_NES_Console.h"
#include "../ConstString/H_NES_ConstString.h"




Huint16 H_NES_APU_Noise_TimerPeriodTable_NTSC[16]={
  2U,4U,8U,16U,32U,48U,64U,80U,101U,127U,190U,254U,381U,508U,1017U,2034U
};
Huint16 H_NES_APU_Noise_TimerPeriodTable_PAL[16]={
  2U,4U,7U,15U,30U,44U,59U,74U,94U,118U,177U,236U,354U,472U,945U,1889U
};
Huint16 H_NES_APU_DMC_TimerPeriodTable_NTSC[16]={
  214U,190U,170U,160U,163U,127U,113U,107U,95U,80U,71U,64U,53U,42U,36U,27U
};
Huint16 H_NES_APU_DMC_TimerPeriodTable_PAL[16]={
  199U,177U,158U,149U,138U,118U,105U,99U,88U,74U,66U,59U,49U,39U,33U,25U
};

#if vH_NES_APU_Enable != 0
static Hbyte PulseSequenceTable[4]={
  0x02U,0x06U,0x1EU,0xF9U
};
#endif
static Hbyte LengthPeriodTable[32]={
  10U,254U,20U,2U,40U,4U,80U,6U,160U,8U,60U,10U,14U,12U,26U,14U,12U,16U,24U,18U,48U,20U,96U,22U,192U,24U,72U,26U,16U,28U,32U,30U
};




static void Reg_4000_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.Pulse1.Reg_4000=Value;
}
static void Reg_4001_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4001_PCnt;
  Huint16 t_uint16;
  Huint16 TargetTimerPeriod;
  Hbyte Shift;

  Reg_4001_PCnt=Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt;

  Reg_4001_PCnt&=(~0xFF00U);
  Reg_4001_PCnt|=(((Huint16)Value)<<8U)|0x0008U;
  
  t_uint16=Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt>>16;
  Shift=Value&0x07U;
  if((Value&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>Shift);
  }else{
    if(Shift==0U){
      TargetTimerPeriod=0U;
    }else{
      TargetTimerPeriod=t_uint16+(~((Huint16)(t_uint16>>Shift)));
    }
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4001_PCnt|=0x0010U;
  }else{
    Reg_4001_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt=Reg_4001_PCnt;
}
static void Reg_4002_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4001_PCnt;
  Hbyte t_byte;
  Huint32 t_uint32;
  Huint16 t_uint16;
  Huint16 TargetTimerPeriod;
  Hbyte Shift;

  t_uint32=Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~0x00FF0000U))|(((Huint32)Value)<<16);
  Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt=t_uint32;

  t_uint16=t_uint32>>16;

  Reg_4001_PCnt=Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt;
  t_byte=Reg_4001_PCnt>>8;
  Shift=t_byte&0x07U;
  if((t_byte&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>Shift);
  }else{
    if(Shift==0U){
      TargetTimerPeriod=0U;
    }else{
      TargetTimerPeriod=t_uint16+(~((Huint16)(t_uint16>>Shift)));
    }
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4001_PCnt|=0x0010U;
  }else{
    Reg_4001_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt=Reg_4001_PCnt;
}
static void Reg_4003_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4001_PCnt;
  Hbyte t_byte;
  Huint16 t_uint16;
  Huint32 t_uint32;
  Huint16 TargetTimerPeriod;
  Hbyte Shift;

  t_uint32=Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~0x07000000U))|((((Huint32)Value)<<24)&0x07000000U);
  Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt=t_uint32;

  t_uint16=t_uint32>>16;

  Reg_4001_PCnt=Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt;
  t_byte=Reg_4001_PCnt>>8;
  Shift=t_byte&0x07U;
  if((t_byte&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>Shift);
  }else{
    if(Shift==0U){
      TargetTimerPeriod=0U;
    }else{
      TargetTimerPeriod=t_uint16+(~((Huint16)(t_uint16>>Shift)));
    }
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4001_PCnt|=0x0010U;
  }else{
    Reg_4001_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt=Reg_4001_PCnt;
  

  t_uint16=(Huint16)LengthPeriodTable[Value>>3];
  if((Console->CPU.APU.Status.Reg_4015_W&0x01U)==0U){
    t_uint16<<=8;
    t_byte=(Hbyte)Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt;
    Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt=((Huint16)t_byte)|t_uint16;
  }else{
    Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt=(t_uint16<<8)|t_uint16;
  }
  Console->CPU.APU.Channel.Pulse1.Sequencer.Step=0x00U;
  Console->CPU.APU.Channel.Pulse1.Envelope.StartFlag=0xFFU;
}

static void Reg_4004_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.Pulse2.Reg_4004=Value;
}
static void Reg_4005_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4005_PCnt;
  Huint16 t_uint16;
  Huint16 TargetTimerPeriod;

  Reg_4005_PCnt=Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt;

  Reg_4005_PCnt&=(~0xFF00U);
  Reg_4005_PCnt|=(((Huint16)Value)<<8U)|0x0008U;
  
  t_uint16=Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt>>16;
  if((Value&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>(Value&0x07U));
  }else{
    TargetTimerPeriod=t_uint16-(t_uint16>>(Value&0x07U));
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4005_PCnt|=0x0010U;
  }else{
    Reg_4005_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt=Reg_4005_PCnt;
}
static void Reg_4006_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4005_PCnt;
  Hbyte t_byte;
  Huint32 t_uint32;
  Huint16 t_uint16;
  Huint16 TargetTimerPeriod;

  t_uint32=Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~0x00FF0000U))|(((Huint32)Value)<<16);
  Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt=t_uint32;

  t_uint16=t_uint32>>16;
  Reg_4005_PCnt=Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt;
  t_byte=Reg_4005_PCnt>>8;
  if((t_byte&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>(t_byte&0x07U));
  }else{
    TargetTimerPeriod=t_uint16-(t_uint16>>(t_byte&0x07U));
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4005_PCnt|=0x0010U;
  }else{
    Reg_4005_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt=Reg_4005_PCnt;
}
static void Reg_4007_Write(Hbyte Value,H_NES_Console* Console){
  Huint16 Reg_4005_PCnt;
  Hbyte t_byte;
  Huint16 t_uint16;
  Huint32 t_uint32;
  Huint16 TargetTimerPeriod;

  t_uint32=Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~0x07000000U))|((((Huint32)Value)<<24)&0x07000000U);
  Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt=t_uint32;

  t_uint16=t_uint32>>16;

  Reg_4005_PCnt=Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt;
  t_byte=Reg_4005_PCnt>>8;
  if((t_byte&0x08U)==0U){
    TargetTimerPeriod=t_uint16+(t_uint16>>(t_byte&0x07U));
  }else{
    TargetTimerPeriod=t_uint16-(t_uint16>>(t_byte&0x07U));
  }
  if((TargetTimerPeriod>0x07FFU)||(t_uint16<8)){
    Reg_4005_PCnt|=0x0010U;
  }else{
    Reg_4005_PCnt&=(~0x0010U);
  }
  Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod=TargetTimerPeriod;
  Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt=Reg_4005_PCnt;

  
  t_uint16=(Huint16)LengthPeriodTable[Value>>3];
  if((Console->CPU.APU.Status.Reg_4015_W&0x02U)==0U){
    t_uint16<<=8;
    t_byte=(Hbyte)Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt;
    Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt=((Huint16)t_byte)|t_uint16;
  }else{
    Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt=(t_uint16<<8)|t_uint16;
  }
  Console->CPU.APU.Channel.Pulse2.Sequencer.Step=0x00U;
  Console->CPU.APU.Channel.Pulse2.Envelope.StartFlag=0xFFU;
}

static void Reg_4008_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt=(Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt&(~0xFF00U))|(((Huint16)Value)<<8);
}
static void Reg_4009_Write(Hbyte Value,H_NES_Console* Console){}
static void Reg_400A_Write(Hbyte Value,H_NES_Console* Console){
  Huint32 t_uint32;

  t_uint32=Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~(0x00FFU<<16)))|(((Huint32)Value)<<16);

  Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt=t_uint32;
}
static void Reg_400B_Write(Hbyte Value,H_NES_Console* Console){
  Hbyte t_byte;
  Huint16 t_uint16;
  Huint32 t_uint32;

  t_uint32=Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt;
  t_uint32=(t_uint32&(~(0x0700U<<16)))|((((Huint32)Value)<<24)&0x07000000U);

  Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt=t_uint32;
  t_uint16=(Huint16)LengthPeriodTable[Value>>3];
  if((Console->CPU.APU.Status.Reg_4015_W&0x04U)==0U){
    t_uint16<<=8;
    t_byte=(Hbyte)Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt;
    Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt=((Huint16)t_byte)|t_uint16;
  }else{
    Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt=(t_uint16<<8)|t_uint16;
  }

  Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt|=0x0080U;
}

static void Reg_400C_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.Noise.Reg_400C=Value;
}
static void Reg_400D_Write(Hbyte Value,H_NES_Console* Console){}
static void Reg_400E_Write(Hbyte Value,H_NES_Console* Console){

  if((Value&0x80U)==0x00U){
    Console->CPU.APU.Channel.Noise.ModeFlag=0x00U;
  }else{
    Console->CPU.APU.Channel.Noise.ModeFlag=0xFFU;
  }

  Console->CPU.APU.Channel.Noise.Timer.Period_Cnt=
    (Console->CPU.APU.Channel.Noise.Timer.Period_Cnt&0x0000FFFFU)
    |(((Huint32)Console->CPU.APU.Channel.Noise.TimerPeriodTable[Value&0x0FU])<<16);
}
static void Reg_400F_Write(Hbyte Value,H_NES_Console* Console){
  Hbyte t_byte;
  Huint16 t_uint16;
  
  t_uint16=(Huint16)LengthPeriodTable[Value>>3];
  if((Console->CPU.APU.Status.Reg_4015_W&0x08U)==0U){
    t_uint16<<=8;
    t_byte=(Hbyte)Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt;
    Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt=((Huint16)t_byte)|t_uint16;
  }else{
    Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt=(t_uint16<<8)|t_uint16;
  }
  Console->CPU.APU.Channel.Noise.Envelope.StartFlag=0xFFU;
}

static void Reg_4010_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.DMC.Reg_4010=Value;

  if((Value&0x80)==0U){
    Console->CPU.Status&=(~vH_NES_CPU_Status_IRQ_APUDMCIRQ);
  }

  Console->CPU.APU.Channel.DMC.Timer.Period_Cnt=
    (Console->CPU.APU.Channel.DMC.Timer.Period_Cnt&0x0000FFFFU)
    |(((Huint32)Console->CPU.APU.Channel.DMC.TimerPeriodTable[Value&0x0FU])<<16);
}
static void Reg_4011_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.DMC.OutputLevel=Value&0x7FU;
}
static void Reg_4012_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.DMC.Reader.Period_Address=0xC000U|(((Huint16)Value)<<6);
}
static void Reg_4013_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Channel.DMC.Reader.Period_NumOfLastByte=(((Huint16)Value)<<4)+0x0001U;
}

static void Reg_4014_Write(Hbyte Value,H_NES_Console* Console){}
static void Reg_4015_Write(Hbyte Value,H_NES_Console* Console){
  Console->CPU.APU.Status.Reg_4015_W=Value;

  if((Value&0x01U)==0U){
    Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt&=(~0x00FFU);
  }
  if((Value&0x02U)==0U){
    Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt&=(~0x00FFU);
  }
  if((Value&0x04U)==0U){
    Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt&=(~0x00FFU);
  }
  if((Value&0x08U)==0U){
    Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt&=(~0x00FFU);
  }

  if((Value&0x10U)==0U){
    Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte=0U;
  }else{
    if(Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte==0U){
      Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte=Console->CPU.APU.Channel.DMC.Reader.Period_NumOfLastByte;
      Console->CPU.APU.Channel.DMC.Reader.Address=Console->CPU.APU.Channel.DMC.Reader.Period_Address;
    }
  }

  Console->CPU.Status&=(~vH_NES_CPU_Status_IRQ_APUDMCIRQ);

}
static void Reg_4016_Write(Hbyte Value,H_NES_Console* Console){}
static void Reg_4017_Write(Hbyte Value,H_NES_Console* Console){

  if((Value&0x40U)!=0U){
    Console->CPU.Status&=(~vH_NES_CPU_Status_IRQ_APUFrameIRQ);
  }

  if((Value&0x80U)!=0U){
    Console->CPU.APU.FrameCounter.Reg_4017_CPUClock=(((Huint32)Value)<<24)|vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
  }else{
    Console->CPU.APU.FrameCounter.Reg_4017_CPUClock=((Huint32)Value)<<24;
  }
}
static void Reg_Exception_Write(Hbyte Value,H_NES_Console* Console){
  //不做任何操作
}

static void (*Reg_Write[32])(Hbyte,H_NES_Console*)={
  Reg_4000_Write,
  Reg_4001_Write,
  Reg_4002_Write,
  Reg_4003_Write,
  Reg_4004_Write,
  Reg_4005_Write,
  Reg_4006_Write,
  Reg_4007_Write,
  Reg_4008_Write,
  Reg_4009_Write,
  Reg_400A_Write,
  Reg_400B_Write,
  Reg_400C_Write,
  Reg_400D_Write,
  Reg_400E_Write,
  Reg_400F_Write,
  Reg_4010_Write,
  Reg_4011_Write,
  Reg_4012_Write,
  Reg_4013_Write,
  Reg_4014_Write,
  Reg_4015_Write,
  Reg_4016_Write,
  Reg_4017_Write,

  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write,
  Reg_Exception_Write
};




Hbyte H_NES_APU_Read(Huint16 Address,H_NES_Console* Console){
  Huint16 Status;
  Hbyte r;

  if(Address==0x4015U){

    r=0x00U;
    Status=Console->CPU.Status;

    if((Status&vH_NES_CPU_Status_IRQ_APUDMCIRQ)!=0U){
      r|=0x80U;
    }
    if((Status&vH_NES_CPU_Status_IRQ_APUFrameIRQ)!=0U){
      r|=0x40U;
    }

    //帧中断被清除
    Console->CPU.Status=Status&(~vH_NES_CPU_Status_IRQ_APUFrameIRQ);

    if(Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte>0U){
      r|=0x10U;
    }
    if((Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt&0x00FFU)>0U){
      r|=0x08U;
    }
    if((Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt&0x00FFU)>0U){
      r|=0x04U;
    }
    if((Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt&0x00FFU)>0U){
      r|=0x02U;
    }
    if((Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt&0x00FFU)>0U){
      r|=0x01U;
    }
    
    return r;
  }

  return Address>>8;
}

void H_NES_APU_Write(Hbyte Value,Huint16 Address,H_NES_Console* Console){
  Reg_Write[Address&0x001FU](Value,Console);
}

Huint32 H_NES_APU_FrameClockGenerate(void* v){
  H_NES_Console* Console;
  
  Huint32 Reg_4017_CPUClock;
  Huint16 CPUClock;
  Huint16 CPUClock_After;

  Console=v;


  Reg_4017_CPUClock=Console->CPU.APU.FrameCounter.Reg_4017_CPUClock;
  CPUClock=Reg_4017_CPUClock&vH_NES_APU_FrameCounter_CPUClock;

  CPUClock_After=CPUClock+4U;

  if((Reg_4017_CPUClock&(0x80U<<24))==0U){
    //4步序列


    if(CPUClock<=7457U){
      if(CPUClock_After>7457U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=14913U){
      if(CPUClock_After>14913U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
      }
    }else if(CPUClock<=22371U){
      if(CPUClock_After>22371U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=29829U){
      if(CPUClock_After>29829U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
        CPUClock_After-=29830U;
      
        if((Reg_4017_CPUClock&(0x40U<<24))==0U){
          //未禁用中断 挂起中断
          Console->CPU.Status|=vH_NES_CPU_Status_IRQ_APUFrameIRQ;
        }
      }
    }else{
      oH_NES_Exception(Console,vH_NES_Result_APUError,H_NES_ConstString_ExceptionAPUStepValueError,CPUClock);
      for(;;){
      }
    }

  }
#if vH_NES_APU_Enable != 0
  else{
    //5步序列

    
    if(CPUClock<=7457U){
      if(CPUClock_After>7457U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=14913U){
      if(CPUClock_After>14913U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
      }
    }else if(CPUClock<=22371U){
      if(CPUClock_After>22371U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=37281U){
      if(CPUClock_After>37281U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
        CPUClock_After-=37282U;
      }
    }else{
      oH_NES_Exception(Console,vH_NES_Result_APUError,H_NES_ConstString_ExceptionAPUStepValueError,CPUClock);
      for(;;){
      }
    }

  }
#endif

  Console->CPU.APU.FrameCounter.Reg_4017_CPUClock=(Reg_4017_CPUClock&(~(vH_NES_APU_FrameCounter_CPUClock|vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame)))|CPUClock_After;

  return Reg_4017_CPUClock;
}

Huint32 H_NES_APU_FrameClockGenerate_PAL(void* v){
  H_NES_Console* Console;
  
  Huint32 Reg_4017_CPUClock;
  Huint16 CPUClock;
  Huint16 CPUClock_After;

  Console=v;


  Reg_4017_CPUClock=Console->CPU.APU.FrameCounter.Reg_4017_CPUClock;
  CPUClock=Reg_4017_CPUClock&vH_NES_APU_FrameCounter_CPUClock;

  CPUClock_After=CPUClock+4U;

  if((Reg_4017_CPUClock&(0x80U<<24))==0U){
    //4步序列


    if(CPUClock<=8313U){
      if(CPUClock_After>8313U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=16627U){
      if(CPUClock_After>16627U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
      }
    }else if(CPUClock<=24939U){
      if(CPUClock_After>24939U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=33252U){
      if(CPUClock_After>33252U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
        CPUClock_After-=33253U;
      
        if((Reg_4017_CPUClock&(0x40U<<24))==0U){
          //未禁用中断 挂起中断
          Console->CPU.Status|=vH_NES_CPU_Status_IRQ_APUFrameIRQ;
        }
      }
    }else{
      oH_NES_Exception(Console,vH_NES_Result_APUError,H_NES_ConstString_ExceptionAPUStepValueError,CPUClock);
      for(;;){
      }
    }

  }
#if vH_NES_APU_Enable != 0
  else{
    //5步序列

    
    if(CPUClock<=8313U){
      if(CPUClock_After>8313U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=16627U){
      if(CPUClock_After>16627U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
      }
    }else if(CPUClock<=24939U){
      if(CPUClock_After>24939U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame;
      }
    }else if(CPUClock<=41565U){
      if(CPUClock_After>41565U){
        Reg_4017_CPUClock|=vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame;
        CPUClock_After-=41566U;
      }
    }else{
      oH_NES_Exception(Console,vH_NES_Result_APUError,H_NES_ConstString_ExceptionAPUStepValueError,CPUClock);
      for(;;){
      }
    }

  }
#endif

  Console->CPU.APU.FrameCounter.Reg_4017_CPUClock=(Reg_4017_CPUClock&(~(vH_NES_APU_FrameCounter_CPUClock|vH_NES_APU_FrameCounter_QuarterFrame|vH_NES_APU_FrameCounter_HalfFrame)))|CPUClock_After;

  return Reg_4017_CPUClock;
}

//4CPU时钟调用一次
void H_NES_APU_Process(H_NES_Console* Console){

  Huint16 Count;

#if vH_NES_APU_Enable != 0
  Huint32 Buffer;//样本: Bit[0:3]:Pulse1 Bit[4:7]:Pulse2 Bit[8:11]:Triangle Bit[12:15]:Noise Bit[16:22]:DMC Bit[24:31]:外部通道 

  Huint16 TargetTimerPeriod;
#endif
  Huint16 ShiftRegister;

#if vH_NES_APU_Enable != 0
  Hbyte t_byte;
#endif
  Hbyte t_byte1;
  Huint16 t_uint16;
  Huint32 t_uint32;


  int OutputIndex;
#if vH_NES_APU_Enable != 0
#if vH_NES_APU_OutputChannelRaw == 0
  Hint32 pulse_out;
  Hint32 tnd_out;

  Hint32 triangle;
  Hint32 noise;
  Hint32 dmc;

  Hint32 a;
  Hint32 outLast;
#endif
#endif


  t_uint32=Console->CPU.APU.FrameCounter.FrameClockGenerate(Console);

#if vH_NES_APU_Enable != 0
  if((t_uint32&vH_NES_APU_FrameCounter_QuarterFrame)!=0U){
    if((t_uint32&vH_NES_APU_FrameCounter_HalfFrame)!=0U){
    
      //执行帧时钟操作 二分之一帧

      //Pulse1
      //LengthCounter
      if((Console->CPU.APU.Status.Reg_4015_W&0x01U)!=0U){
        if((Console->CPU.APU.Channel.Pulse1.Reg_4000&0x20U)==0U){
          t_uint16=Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt;
          if((t_uint16&0x00FFU)!=0U){
            Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt=t_uint16-1U;
          }
        }
      }
      //Sweep
      t_uint16=Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt;
      if((t_uint16&(0x0017U|(0x80U<<8)))==(0x80U<<8)){
        //SetTimer

        TargetTimerPeriod=Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod;
        t_byte=t_uint16>>8;
        t_byte1=t_byte&0x07U;
        if(t_byte1!=0U){
          t_uint32=Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt;
          Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt=(t_uint32&(~0x07FF0000U))|(((Huint32)TargetTimerPeriod)<<16);

          if((t_byte&0x08U)==0U){
            TargetTimerPeriod=TargetTimerPeriod+(TargetTimerPeriod>>t_byte1);
          }else{
            TargetTimerPeriod=TargetTimerPeriod+(~((Huint16)(TargetTimerPeriod>>t_byte1)));
          }
          Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod=TargetTimerPeriod;
          if(TargetTimerPeriod>0x07FFU){
            t_uint16|=0x0010U;//标记静音
          }
        }

      }
      if(((t_uint16&0x0007U)==0U)||((t_uint16&0x0008U)!=0U)){
        t_uint16=(t_uint16&(~0x000FU))|((t_uint16>>12)&0x0007U);
      }else{
        t_uint16--;
      }
      Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt=t_uint16;
      
      //Pulse2
      //LengthCounter
      if((Console->CPU.APU.Status.Reg_4015_W&0x02U)!=0U){
        if((Console->CPU.APU.Channel.Pulse2.Reg_4004&0x20U)==0U){
          t_uint16=Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt;
          if((t_uint16&0x00FFU)!=0U){
            Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt=t_uint16-1U;
          }
        }
      }
      //Sweep
      t_uint16=Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt;
      if((t_uint16&(0x0017U|(0x80U<<8)))==(0x80U<<8)){
        //SetTimer

        TargetTimerPeriod=Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod;
        t_byte=t_uint16>>8;
        t_byte1=t_byte&0x07U;
        if(t_byte1!=0U){
          t_uint32=Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt;
          Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt=(t_uint32&(~0x07FF0000U))|(((Huint32)TargetTimerPeriod)<<16);

          if((t_byte&0x08U)==0U){
            TargetTimerPeriod=TargetTimerPeriod+(TargetTimerPeriod>>t_byte1);
          }else{
            TargetTimerPeriod=TargetTimerPeriod-(TargetTimerPeriod>>t_byte1);
          }
          Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod=TargetTimerPeriod;
          if(TargetTimerPeriod>0x07FFU){
            t_uint16|=0x0010U;//标记静音
          }
        }
      }
      if(((t_uint16&0x0007U)==0U)||((t_uint16&0x0008U)!=0U)){
        t_uint16=(t_uint16&(~0x000FU))|((t_uint16>>12)&0x0007U);
      }else{
        t_uint16--;
      }
      Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt=t_uint16;
      
      //Triangle
      //LengthCounter
      if((Console->CPU.APU.Status.Reg_4015_W&0x04U)!=0U){
        if((Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt&0x8000U)==0U){
          t_uint16=Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt;
          if((t_uint16&0x00FFU)!=0U){
            Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt=t_uint16-1U;
          }
        }
      }

      //Noise
      //LengthCounter
      if((Console->CPU.APU.Status.Reg_4015_W&0x08U)!=0U){
        if((Console->CPU.APU.Channel.Noise.Reg_400C&0x20U)==0U){
          t_uint16=Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt;
          if((t_uint16&0x00FFU)!=0U){
            Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt=t_uint16-1U;
          }
        }
      }
      
    }
    
    //执行帧时钟操作 四分之一帧

    //Pulse1
    //Envelope
    if(Console->CPU.APU.Channel.Pulse1.Envelope.StartFlag==0U){
      t_byte=Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue;
      if(t_byte>0U){
        Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue=t_byte-0x1U;
      }else{
        t_byte1=Console->CPU.APU.Channel.Pulse1.Reg_4000;
        Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue=t_byte1&0x0FU;
        t_byte=Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel;
        if(t_byte>0U){
          Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel=t_byte-0x1U;
        }else{
          if((t_byte1&0x20U)!=0U){
            Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel=0x0FU;
          }
        }
      }
    }else{
      Console->CPU.APU.Channel.Pulse1.Envelope.StartFlag=0U;
      Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue=Console->CPU.APU.Channel.Pulse1.Reg_4000&0x0FU;
      Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel=0x0FU;
    }

    //Pulse2
    //Envelope
    if(Console->CPU.APU.Channel.Pulse2.Envelope.StartFlag==0U){
      t_byte=Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue;
      if(t_byte>0U){
        Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue=t_byte-0x1U;
      }else{
        t_byte1=Console->CPU.APU.Channel.Pulse2.Reg_4004;
        Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue=t_byte1&0x0FU;
        t_byte=Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel;
        if(t_byte>0U){
          Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel=t_byte-0x1U;
        }else{
          if((t_byte1&0x20U)!=0U){
            Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel=0x0FU;
          }
        }
      }
    }else{
      Console->CPU.APU.Channel.Pulse2.Envelope.StartFlag=0U;
      Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue=Console->CPU.APU.Channel.Pulse2.Reg_4004&0x0FU;
      Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel=0x0FU;
    }
    
    //Triangle
    //LinerCounter
    t_uint16=Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt;
    if((t_uint16&0x0080U)!=0U){
      t_uint16=(t_uint16&(~0x007FU))|((t_uint16&0x7F00U)>>8);
    }else if((t_uint16&0x007FU)!=0U){
      t_uint16--;
    }
    if((t_uint16&0x8000U)==0U){
      t_uint16&=(~0x0080U);
    }
    Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt=t_uint16;

    //Noise
    //Envelope
    if(Console->CPU.APU.Channel.Noise.Envelope.StartFlag==0U){
      t_byte=Console->CPU.APU.Channel.Noise.Envelope.DividerValue;
      if(t_byte>0U){
        Console->CPU.APU.Channel.Noise.Envelope.DividerValue=t_byte-0x1U;
      }else{
        t_byte1=Console->CPU.APU.Channel.Noise.Reg_400C;
        Console->CPU.APU.Channel.Noise.Envelope.DividerValue=t_byte1&0x0FU;
        t_byte=Console->CPU.APU.Channel.Noise.Envelope.DecayLevel;
        if(t_byte>0U){
          Console->CPU.APU.Channel.Noise.Envelope.DecayLevel=t_byte-0x1U;
        }else{
          if((t_byte1&0x20U)!=0U){
            Console->CPU.APU.Channel.Noise.Envelope.DecayLevel=0x0FU;
          }
        }
      }
    }else{
      Console->CPU.APU.Channel.Noise.Envelope.StartFlag=0U;
      Console->CPU.APU.Channel.Noise.Envelope.DividerValue=Console->CPU.APU.Channel.Noise.Reg_400C&0x0FU;
      Console->CPU.APU.Channel.Noise.Envelope.DecayLevel=0x0FU;
    }
    
  }
#endif


#if vH_NES_APU_Enable != 0
  Buffer=0U;


  //Pulse1
  t_byte=Console->CPU.APU.Channel.Pulse1.Sequencer.Step;
  t_uint32=Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt;
  t_uint16=t_uint32>>16;
  Count=t_uint32&0x00007FFU;
  if(Count>=2U){
    t_uint32-=2U;
  }else{
    if(t_uint16>1U){
      Count=t_uint16-(1U-Count);
      t_uint32=(((Huint32)t_uint16)<<16)+Count;
    }

    t_byte=(t_byte-0x01U)&0x07U;
    Console->CPU.APU.Channel.Pulse1.Sequencer.Step=t_byte;
  }
  Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt=t_uint32;
  t_byte1=Console->CPU.APU.Channel.Pulse1.Reg_4000;//预取$4000
  if(((Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt&0x00FFU)!=0U)
  &&(t_uint16>7U)
  &&((PulseSequenceTable[t_byte1>>6]&(0x01U<<t_byte))!=0U)
  &&((Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt&0x0010U)==0U)){
    if((t_byte1&0x10U)==0U){
      t_byte=Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel;
    }else{
      t_byte=t_byte1&0x0FU;
    }
    Buffer|=(Huint32)t_byte;
  }


  //Pulse2
  t_byte=Console->CPU.APU.Channel.Pulse2.Sequencer.Step;
  t_uint32=Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt;
  t_uint16=t_uint32>>16;
  Count=t_uint32&0x00007FFU;
  if(Count>=2U){
    t_uint32-=2U;
  }else{
    if(t_uint16>1U){
      Count=t_uint16-(1U-Count);
      t_uint32=(((Huint32)t_uint16)<<16)+Count;
    }

    t_byte=(t_byte-0x01U)&0x07U;
    Console->CPU.APU.Channel.Pulse2.Sequencer.Step=t_byte;
  }
  Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt=t_uint32;
  t_byte1=Console->CPU.APU.Channel.Pulse2.Reg_4004;//预取$4004
  if(((Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt&0x00FFU)!=0U)
  &&(t_uint16>7U)
  &&((PulseSequenceTable[t_byte1>>6]&(0x01U<<t_byte))!=0U)
  &&((Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt&0x0010U)==0U)){
    if((t_byte1&0x10U)==0U){
      t_byte=Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel;
    }else{
      t_byte=t_byte1&0x0FU;
    }
    Buffer|=((Huint32)t_byte)<<4;
  }


  //Triangle
  t_byte=Console->CPU.APU.Channel.Triangle.Output;
  t_uint32=Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt;
  t_uint16=t_uint32>>16;
  if(t_uint16<3U){
    //静音通道

    if((t_byte&0x0FU)!=0U){
      if((t_byte&0x80U)==0U){
        if(t_byte==0x0FU){
          t_byte=0x8FU;
        }else{
          t_byte++;
        }
      }else{
        if(t_byte==0x80U){
          t_byte=0x00U;
        }else{
          t_byte--;
        }
      }
      Console->CPU.APU.Channel.Triangle.Output=t_byte;
    }

  }else{
    Count=t_uint32&0x00007FFU;
    if(Count>=4U){
      t_uint32-=4U;
    }else{
      if(t_uint16>3U){
        Count=t_uint16-(3U-Count);
        t_uint32=(((Huint32)t_uint16)<<16)+Count;
      }

      if(((t_byte&0x0FU)!=0U)||
        (((Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt&0x007FU)!=0U)
        &&((Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt&0x00FFU)!=0U))){

        if((t_byte&0x80U)==0U){
          if(t_byte==0x0FU){
            t_byte=0x8FU;
          }else{
            t_byte++;
          }
        }else{
          if(t_byte==0x80U){
            t_byte=0x00U;
          }else{
            t_byte--;
          }
        }
        Console->CPU.APU.Channel.Triangle.Output=t_byte;
      }
    }

    Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt=t_uint32;
  }
  Buffer|=(((Huint32)t_byte)<<8)&0x00000F00U;
  


  //Noise
  ShiftRegister=Console->CPU.APU.Channel.Noise.ShiftRegister;
  t_uint32=Console->CPU.APU.Channel.Noise.Timer.Period_Cnt;
  Count=t_uint32&0x00007FFU;
  if(Count>=2U){
    t_uint32-=2U;
  }else{
    t_uint16=t_uint32>>16;
    if(t_uint16>1U){
      Count=t_uint16-(1U-Count);
      t_uint32=(((Huint32)t_uint16)<<16)+Count;
    }

    if(Console->CPU.APU.Channel.Noise.ModeFlag==0U){
      ShiftRegister=(ShiftRegister>>1)|(((ShiftRegister<<14)^(ShiftRegister<<13))&0x4000U);
    }else{
      ShiftRegister=(ShiftRegister>>1)|(((ShiftRegister<<14)^(ShiftRegister<<8))&0x4000U);
    }
    Console->CPU.APU.Channel.Noise.ShiftRegister=ShiftRegister;
  }
  Console->CPU.APU.Channel.Noise.Timer.Period_Cnt=t_uint32;
  if((ShiftRegister&0x00001U)==0U){
    if((Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt&0x00FFU)!=0U){
      t_byte1=Console->CPU.APU.Channel.Noise.Reg_400C;
      if((t_byte1&0x10U)==0U){
        t_byte=Console->CPU.APU.Channel.Noise.Envelope.DecayLevel;
      }else{
        t_byte=t_byte1&0x0FU;
      }
      Buffer|=(((Huint32)t_byte)<<12)&0x0000F000U;
    }
  }
#endif

  //DMC
#if vH_NES_APU_Enable != 0
  t_byte=Console->CPU.APU.Channel.DMC.OutputLevel;
#endif
  t_uint32=Console->CPU.APU.Channel.DMC.Timer.Period_Cnt;
  Count=t_uint32&0x00007FFU;
  if(Count>=2U){
    t_uint32-=2U;
  }else{
    t_uint16=t_uint32>>16;
    if(t_uint16>1U){
      Count=t_uint16-(1U-Count);
      t_uint32=(((Huint32)t_uint16)<<16)+Count;
    }

#if vH_NES_APU_Enable != 0
    ShiftRegister=Console->CPU.APU.Channel.DMC.Shifter.Value;
    if(Console->CPU.APU.Channel.DMC.MultFlag==0U){
      if((ShiftRegister&0x01U)==0U){
        if(t_byte>0x01U){
          t_byte-=0x02U;
          Console->CPU.APU.Channel.DMC.OutputLevel=t_byte;
        }
      }else{
        if(t_byte<0x7EU){
          t_byte+=0x02U;
          Console->CPU.APU.Channel.DMC.OutputLevel=t_byte;
        }
      }
    }
    Console->CPU.APU.Channel.DMC.Shifter.Value=ShiftRegister>>1U;
#endif
    
    t_byte1=Console->CPU.APU.Channel.DMC.Shifter.NumOfLastBit;
    if(t_byte1<2){
      Console->CPU.APU.Channel.DMC.Shifter.NumOfLastBit=0x08U;//重新设置计数
        
      //DMC 取音频样本刷新
      Count=Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte;
      if(Count>0U){
        Count--;
        Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte=Count;
        ShiftRegister=Console->CPU.APU.Channel.DMC.Reader.Address;
        Console->CPU.APU.Channel.DMC.Shifter.Value=Console->Cartridge.PRG_Read(ShiftRegister,Console);
        Console->CPU.APU.Channel.DMC.Reader.Address=(ShiftRegister+0x0001U)|0x8000U;
        if(Count==0U){
          if((Console->CPU.APU.Channel.DMC.Reg_4010&0x40U)==0U){
            if((Console->CPU.APU.Channel.DMC.Reg_4010&0x80U)!=0U){
              Console->CPU.Status|=vH_NES_CPU_Status_IRQ_APUDMCIRQ;
            }
          }else{
            Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte=Console->CPU.APU.Channel.DMC.Reader.Period_NumOfLastByte;
            Console->CPU.APU.Channel.DMC.Reader.Address=Console->CPU.APU.Channel.DMC.Reader.Period_Address;
          }
        }

        Console->CPU.APU.Channel.DMC.MultFlag=0x00U;
      }else{
        Console->CPU.APU.Channel.DMC.MultFlag=0xFFU;
      }
    }else{
      Console->CPU.APU.Channel.DMC.Shifter.NumOfLastBit=t_byte1-0x01U;//正常递减
    }
    
  }
  Console->CPU.APU.Channel.DMC.Timer.Period_Cnt=t_uint32;
#if vH_NES_APU_Enable != 0
  Buffer|=(((Huint32)t_byte)<<16)&0x007F0000U;
  



#if vH_NES_APU_OutputChannelRaw == 0
  /*
    output = pulse_out + tnd_out

                              95.88                               3141699*(pulse1 + pulse2)
    pulse_out = ------------------------------------ * 32767 =  ----------------------------
                (8128 / (pulse1 + pulse2)) + 100                 8128+100*(pulse1 + pulse2)

                                          159.79                                                                 5235838
    tnd_out = ------------------------------------------------------------- * 32767 =   --------------------------------------------------------
                                        1                                                                  2147483647
              ----------------------------------------------------- + 100                ---------------------------------------------- + 100
                (triangle / 8227) + (noise / 12241) + (dmc / 22638)                        (triangle*261028 + noise*175433 + dmc*94861)
  */

  pulse_out=(Hint32)((Buffer&0x0000000FU)+((Buffer>>4)&0x0000000FU));
  if(pulse_out!=0){
    pulse_out=3141699*pulse_out/(pulse_out*100+8128);
  }

  if((Buffer&0x007FFF00U)!=0U){
    triangle=(Hint32)((Buffer>>8)&0x0000000FU);
    noise=(Hint32)((Buffer>>12)&0x0000000FU);
    dmc=(Hint32)(Buffer>>16);
    tnd_out=5235838/(2147483647/(triangle*261028+noise*175433+dmc*94861)+100);
  }else{
    tnd_out=0;
  }
  
  tnd_out+=pulse_out;

  a=Console->CPU.APU.Output.LPF.a;
  outLast=Console->CPU.APU.Output.LPF.last;
  tnd_out=outLast+(tnd_out-outLast)*65536/a;
  Console->CPU.APU.Output.LPF.last=tnd_out;
  

  //输出样本
  OutputIndex=Console->CPU.APU.Output.DivCnt;
  if(OutputIndex>0){
    Console->CPU.APU.Output.DivCnt=OutputIndex-1;
  }else{
    Console->CPU.APU.Output.DivCnt=vH_NES_APU_OutputDiv-1;

    OutputIndex=Console->CPU.APU.Output.OutputIndex;
    ((Hint16*)Console->CPU.APU.Output.Buffer)[OutputIndex]=tnd_out;
    if(OutputIndex==(vH_NES_APU_NumOfOutputSample-1)){
      Console->CPU.APU.Output.OutputIndex=0;
      Console->LL_Function.Console.AudioOutput(Console->LL_Function.v,Console->CPU.APU.Output.Buffer,vH_NES_APU_NumOfOutputSample);
    }else{
      Console->CPU.APU.Output.OutputIndex=OutputIndex+1;
    }
  }
#else
  //输出样本
  OutputIndex=Console->CPU.APU.Output.OutputIndex;
  ((Huint32*)Console->CPU.APU.Output.Buffer)[OutputIndex]=Buffer;
  if(OutputIndex==(vH_NES_APU_NumOfOutputSample-1)){
    Console->CPU.APU.Output.OutputIndex=0;
    Console->LL_Function.Console.AudioOutput(Console->LL_Function.v,Console->CPU.APU.Output.Buffer,vH_NES_APU_NumOfOutputSample);
  }else{
    Console->CPU.APU.Output.OutputIndex=OutputIndex+1;
  }
#endif
#else
#if vH_NES_APU_OutputChannelRaw == 0
  //输出样本
  OutputIndex=Console->CPU.APU.Output.DivCnt;
  if(OutputIndex>0){
    Console->CPU.APU.Output.DivCnt=OutputIndex-1;
  }else{
    Console->CPU.APU.Output.DivCnt=vH_NES_APU_OutputDiv-1;

    OutputIndex=Console->CPU.APU.Output.OutputIndex;
    if(OutputIndex==(vH_NES_APU_NumOfOutputSample-1)){
      Console->CPU.APU.Output.OutputIndex=0;
      Console->LL_Function.Console.AudioOutput(Console->LL_Function.v,NULL,vH_NES_APU_NumOfOutputSample);
    }else{
      Console->CPU.APU.Output.OutputIndex=OutputIndex+1;
    }
  }
#else
  //输出样本
  OutputIndex=Console->CPU.APU.Output.OutputIndex;
  if(OutputIndex==(vH_NES_APU_NumOfOutputSample-1)){
    Console->CPU.APU.Output.OutputIndex=0;
    Console->LL_Function.Console.AudioOutput(Console->LL_Function.v,NULL,vH_NES_APU_NumOfOutputSample);
  }else{
    Console->CPU.APU.Output.OutputIndex=OutputIndex+1;
  }
#endif
#endif
  
}



